package com.imut.lagain.filter;

import com.imut.lagain.service.IUserRoleService;
import com.imut.lagain.util.JwtUtil;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * JWT认证过滤器
 * 用于验证请求中的JWT令牌并设置安全上下文
 */
@Component
@RequiredArgsConstructor
public class JwtAuthenticationFilter extends OncePerRequestFilter {
    private static final Logger log = LoggerFactory.getLogger(JwtAuthenticationFilter.class);
    
    private final JwtUtil jwtUtil;
    private final IUserRoleService userRoleService;
    
    private static final String AUTHORIZATION_HEADER = "Authorization";
    private static final String BEARER_PREFIX = "Bearer ";
    
    @Override
    protected void doFilterInternal(
            HttpServletRequest request, 
            HttpServletResponse response, 
            FilterChain filterChain) throws ServletException, IOException {
        
        try {
            log.info("从请求头中获取JWT令牌");
            String token = extractTokenFromRequest(request);
            
            log.info("如果令牌存在且有效，则设置认证信息");
            if (StringUtils.hasText(token) && jwtUtil.validateToken(token)) {
                setAuthenticationContext(token, request);
            }
            
        } catch (Exception e) {
            log.error("JWT authentication failed: {}", e.getMessage());
            log.info("认证失败时清除安全上下文");
            SecurityContextHolder.clearContext();
        }
        
        log.info("继续过滤器链");
        filterChain.doFilter(request, response);
    }
    
    /**
     * 从请求中提取JWT令牌
     * @param request HTTP请求
     * @return JWT令牌，如果不存在则返回null
     */
    private String extractTokenFromRequest(HttpServletRequest request) {
        String bearerToken = request.getHeader(AUTHORIZATION_HEADER);
        if (StringUtils.hasText(bearerToken) && bearerToken.startsWith(BEARER_PREFIX)) {
            return bearerToken.substring(BEARER_PREFIX.length());
        }
        return null;
    }
    
    /**
     * 设置认证上下文
     * @param token JWT令牌
     * @param request HTTP请求
     */
    private void setAuthenticationContext(String token, HttpServletRequest request) {
        try {
            log.info("从令牌中获取用户信息");
            String openId = jwtUtil.getOpenIdFromToken(token);
            Long userId = jwtUtil.getUserIdFromToken(token);
            
            if (StringUtils.hasText(openId) && userId != null) {
                log.info("创建认证对象");
                log.info("这里可以根据需要添加用户角色和权限");
                List<SimpleGrantedAuthority> authorities = getAuthorities(userId);
                
                UsernamePasswordAuthenticationToken authentication = 
                    new UsernamePasswordAuthenticationToken(
                        openId,     // principal
                        null,       // credentials
                        authorities // authorities
                    );
                
                log.info("设置请求详情");
                authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                
                log.info("将认证信息设置到安全上下文中");
                SecurityContextHolder.getContext().setAuthentication(authentication);
                
                log.info("将用户ID添加到请求属性中，方便控制器使用");
                request.setAttribute("userId", userId);
                request.setAttribute("openId", openId);
                
                log.debug("JWT authentication successful for user: {}", openId);
            }
            
        } catch (Exception e) {
            log.error("Failed to set authentication context: {}", e.getMessage());
            SecurityContextHolder.clearContext();
        }
    }
    
    /**
     * 获取用户权限
     * @param userId 用户ID
     * @return 权限列表
     */
    private List<SimpleGrantedAuthority> getAuthorities(Long userId) {
        List<SimpleGrantedAuthority> authorities = new ArrayList<>();
        
        try {
            log.info("默认给所有用户USER角色");
            authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
            
            log.info("根据用户角色添加相应权限");
            if (userRoleService.isAdmin(userId)) {
                authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
                log.debug("Added ADMIN role for user: {}", userId);
            } else if (userRoleService.isPartner(userId)) {
                authorities.add(new SimpleGrantedAuthority("ROLE_PARTNER"));
                log.debug("Added PARTNER role for user: {}", userId);
            }
            
        } catch (Exception e) {
            log.error("Failed to get authorities for user: {}", userId, e);
            log.info("发生异常时返回默认权限");
            return Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER"));
        }
        
        return authorities;
    }
    
    /**
     * 判断是否为管理员
     * @param userId 用户ID
     * @return 是否为管理员
     */
    private boolean isAdmin(Long userId) {
        try {
            return userRoleService.isAdmin(userId);
        } catch (Exception e) {
            log.error("Failed to check admin status for user: {}", userId, e);
            return false;
        }
    }
    
    /**
     * 判断是否为合作伙伴
     * @param userId 用户ID
     * @return 是否为合作伙伴
     */
    private boolean isPartner(Long userId) {
        try {
            return userRoleService.isPartner(userId);
        } catch (Exception e) {
            log.error("Failed to check partner status for user: {}", userId, e);
            return false;
        }
    }
    
    @Override
    protected boolean shouldNotFilter(HttpServletRequest request) {
        String path = request.getRequestURI();
        
        log.info("检查路径是否需要跳过JWT验证: {}", path);
        boolean shouldSkip = path.startsWith("/auth/") ||
               path.startsWith("/files/download/") ||
               path.startsWith("/capsules/share/") ||
               path.equals("/error") ||
               path.startsWith("/actuator/") ||
               path.startsWith("/swagger-ui/") ||
               path.startsWith("/v3/api-docs/") ||
               path.equals("/favicon.ico");
        
        log.info("路径 {} 是否跳过JWT验证: {}", path, shouldSkip);
        return shouldSkip;
    }
}
